#include <iostream>
#include <memory>
#include <string>
#include <fstream>

#include <grpcpp/grpcpp.h>

#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "gp_lua.grpc.pb.h"
#endif

#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <string.h>
#include "c_call_lua.h"


using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using gp_lua::AxisMoveParam;
using gp_lua::Response;
using gp_lua::EmptyRequest;
using gp_lua::OpenLid;
using gp_lua::DP1_Lua;
using gp_lua::DP8_Lua;
using gp_lua::XR_lua;

using grpc::ServerReader;
using grpc::ServerReaderWriter;
using grpc::ServerWriter;


#define lua_script_path "/home/hcgy/lua/lua_scripts/"

const char * lua_files[4] = 
{
   "openlid.lua",
   "dp1.lua",
   "dp8.lua",
   "zr.lua",
};

typedef enum
{
    I_LUA_OPENLID,
    I_LUA_DP1,
    I_LUA_DP8,
    I_LUA_ZR,
}en_lua_file_index;

class OpenLidServiceImpl final : public OpenLid::Service {
  Status open(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in OpenLid open\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_OPENLID]);

    lua_execute(fileNameBuff,"open");   
    return Status::OK;
  }

  Status close(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in OpenLid close\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_OPENLID]);

    lua_execute(fileNameBuff,"close");   
    return Status::OK;
  }

  
};

class DP1_LuaServiceImpl final : public DP1_Lua::Service {
  Status DP1_TransTube(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in DP1_Lua TransTube\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_DP1]);

    lua_execute(fileNameBuff,"trans_tube");   
    return Status::OK;
  }
  
  Status suck_spit(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in DP1_Lua suck_spit\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_DP1]);

    lua_execute(fileNameBuff,"suck_spit");   
    return Status::OK;
  }
  
};

class DP8_LuaServiceImpl final : public DP8_Lua::Service {
  Status suck_spit(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in DP8_Lua suck_spit\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_DP8]);

    lua_execute(fileNameBuff,"suck_spit");   
    return Status::OK;
  }

  
};

class ZR_LuaServiceImpl final : public XR_lua::Service {
  Status heat_seal(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {
    
    printf("enter in XR_lua heat_seal\n");
    char fileNameBuff[128];
    memset(fileNameBuff,0,128);
    sprintf(fileNameBuff,"%s%s",lua_script_path,lua_files[I_LUA_ZR]);

    lua_execute(fileNameBuff,"heat_seal");   
    return Status::OK;
  }

  
};

#define PURIFY_LUA_SERVER_IP "0.0.0.0:30051"

Server * ptrServer;

void RunServer() {
  std::string server_address(PURIFY_LUA_SERVER_IP);
  OpenLidServiceImpl serviceOpenLid;
  DP1_LuaServiceImpl serviceDp1;
  DP8_LuaServiceImpl serviceDp8;
  ZR_LuaServiceImpl serviceXR;

  ServerBuilder builder;
  // Listen on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  // Register "service" as the instance through which we'll communicate with
  // clients. In this case it corresponds to an *synchronous* service.
  builder.RegisterService(&serviceOpenLid);
  builder.RegisterService(&serviceDp1);
  builder.RegisterService(&serviceDp8);
  builder.RegisterService(&serviceXR);
  // Finally assemble the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;

  // Wait for the server to shutdown. Note that some other thread must be
  // responsible for shutting down the server for this call to ever return.
  
  ptrServer = server.get();
  server->Wait();
  //server->Shutdown();

}

extern int initLuaActMsg(void);

extern int deinitLuaActMsg(void);

void handler(int data)
{ 
    printf("sig is %d\n", data);
    
    ptrServer->Shutdown();
    deinitLuaActMsg();
    system("exit 0");
}



int main(int argc, char** argv) {
  initLuaActMsg();
  signal(SIGTERM, handler);
  RunServer();

  return 0;
}